<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Highscore - Boost C++ 库 - 函数对象</title>
<link rel="stylesheet" href="css/highscore.css" type="text/css">
<link rev="made" href="mailto:boris@highscore.de">
<link rel="home" href="frontpage.html" title="Boost C++ 库">
<link rel="up" href="frontpage.html" title="Boost C++ 库">
<link rel="prev" href="functionobjects.html" title="第 2 章 函数对象">
<link rel="next" href="eventhandling.html" title="第 4 章 事件处理">
<link rel="chapter" href="introduction.html" title="第 1 章 简介">
<link rel="chapter" href="functionobjects.html" title="第 2 章 函数对象">
<link rel="chapter" href="functionobjects.html" title="第 3 章 函数对象">
<link rel="chapter" href="eventhandling.html" title="第 4 章 事件处理">
<link rel="chapter" href="asio.html" title="第 5 章 异步输入输出">
<link rel="chapter" href="asio.html" title="第 6 章 异步输入输出">
<link rel="chapter" href="asio.html" title="第 7 章 异步输入输出">
<link rel="chapter" href="interprocesscommunication.html" title="第 8 章 进程间通讯">
<link rel="chapter" href="castoperators.html" title="第 9 章 类型转换操作符">
<link rel="chapter" href="castoperators.html" title="第 10 章 类型转换操作符">
<link rel="chapter" href="castoperators.html" title="第 11 章 类型转换操作符">
<link rel="chapter" href="castoperators.html" title="第 12 章 类型转换操作符">
<link rel="chapter" href="castoperators.html" title="第 13 章 类型转换操作符">
<link rel="chapter" href="castoperators.html" title="第 14 章 类型转换操作符">
<link rel="chapter" href="castoperators.html" title="第 15 章 类型转换操作符">
<link rel="chapter" href="castoperators.html" title="第 16 章 类型转换操作符">
<link rel="section" href="functionobjects.html#functionobjects_general" title="3.1. 概述">
<link rel="section" href="functionobjects.html#functionobjects_bind" title="3.2. Boost.Bind">
<link rel="section" href="functionobjects.html#functionobjects_ref" title="3.3. Boost.Ref">
<link rel="section" href="functionobjects.html#functionobjects_function" title="3.4. Boost.Function">
<link rel="section" href="functionobjects.html#functionobjects_lambda" title="3.5. Boost.Lambda">
<link rel="section" href="functionobjects.html#functionobjects_exercises" title="3.6. 练习">
<meta http-equiv="pics-label" content='(pics-1.1 "http://www.icra.org/ratingsv02.html" l gen true for "http://www.highscore.de" r (nz 1 vz 1 lz 1 oz 1 cz 1) gen true for "http://highscore.de" r (nz 1 vz 1 lz 1 oz 1 cz 1))'>
<meta http-equiv="Content-Style-Type" content="text/css">
<meta http-equiv="Content-Script-Type" content="text/javascript">
<link href="http://www.highscore.de/favicon.ico" rel="shortcut icon" type="image/vnd.microsoft.icon">
<script type="text/javascript" src="js/jquery-1.3.2.min.js"></script><script type="text/javascript" src="js/jquery.event.drag-1.5.min.js"></script><script type="text/javascript" src="js/highscore.js"></script>
</head>
<body>
<div lang="zh" class="docbook chapter" title="第 3 章 函数对象">
<p class="title">Boost C++ 库</p>
<script type="text/javascript">
          var titlepage = "导言";
        
      var titles = new Array(titlepage,
      
        "第 1 章 简介",
      
        "第 2 章 函数对象",
      
        "第 3 章 函数对象",
      
        "第 4 章 事件处理",
      
        "第 5 章 异步输入输出",
      
        "第 6 章 异步输入输出",
      
        "第 7 章 异步输入输出",
      
        "第 8 章 进程间通讯",
      
        "第 9 章 类型转换操作符",
      
        "第 10 章 类型转换操作符",
      
        "第 11 章 类型转换操作符",
      
        "第 12 章 类型转换操作符",
      
        "第 13 章 类型转换操作符",
      
        "第 14 章 类型转换操作符",
      
        "第 15 章 类型转换操作符",
      
        "第 16 章 类型转换操作符",
      
      "");

      
          var titlehtml = "frontpage.html";
        
      var filenames = new Array(titlehtml,
      
        "introduction.html",
      
        "functionobjects.html",
      
        "functionobjects.html",
      
        "eventhandling.html",
      
        "asio.html",
      
        "asio.html",
      
        "asio.html",
      
        "interprocesscommunication.html",
      
        "castoperators.html",
      
        "castoperators.html",
      
        "castoperators.html",
      
        "castoperators.html",
      
        "castoperators.html",
      
        "castoperators.html",
      
        "castoperators.html",
      
        "castoperators.html",
      
      "");

      
      document.open();
      document.write('<form action="" class="toc">');
      document.write('<select size="1" onchange="location.href=options[selectedIndex].value">');
      for (var i = 0; i < titles.length && i < filenames.length; ++i) {
        if (titles[i] != "" && filenames[i] != "") {
          document.write('<option');
          document.write(' value="' + filenames[i] + '"');
          var expr = new RegExp('[/\]' + filenames[i] + '$');
          if (expr.test(location.href)) {
            document.write(' selected="selected"');
          }
          document.write('>' + titles[i] + '<\/option>');
        }
      }
      document.write('<\/select>');
      document.write('<\/form>');
      document.close();
      
    </script><noscript><p class="toc"><a href="toc.html">目录</a></p></noscript>
<hr class="hrhead">
<h1 class="title">
<a name="functionobjects"></a>第 3 章 函数对象</h1>
<hr>
<div class="toc">
<h3>目录</h3>
<ul>
<li><span class="sect1"><a href="functionobjects.html#functionobjects_general">3.1 概述</a></span></li>
<li><span class="sect1"><a href="functionobjects.html#functionobjects_bind">3.2 Boost.Bind</a></span></li>
<li><span class="sect1"><a href="functionobjects.html#functionobjects_ref">3.3 Boost.Ref</a></span></li>
<li><span class="sect1"><a href="functionobjects.html#functionobjects_function">3.4 Boost.Function</a></span></li>
<li><span class="sect1"><a href="functionobjects.html#functionobjects_lambda">3.5 Boost.Lambda</a></span></li>
<li><span class="sect1"><a href="functionobjects.html#functionobjects_exercises">3.6 练习</a></span></li>
</ul>
</div>
<p class="license"><a href="http://creativecommons.org/licenses/by-nc-nd/3.0/de/deed.zh" rel="license" target="_top"><img src="img/88x31_cc_logo.gif" alt="" width="88" height="31"></a> 该书采用 <a href="http://creativecommons.org/licenses/by-nc-nd/3.0/de/deed.zh" rel="license" target="_top">Creative Commons License</a> 授权</p>
<hr>
<h2 class="title">
<a name="functionobjects_general"></a>3.1. 概述</h2>
<div class="sect1">
<p>本章介绍的是函数对象，可能称为'高阶函数'更为适合。 它实际上是指那些可以被传入到其它函数或是从其它函数返回的一类函数。
    在C++中高阶函数是被实现为函数对象的，所以这个标题还是有意义的。</p>
<p>在这整一章中，将会介绍几个用于处理函数对象的 Boost C++ 库。 其中，<a class="link" href="http://www.boost.org/libs/bind/">Boost.Bind</a>
    可替换来自C++标准的著名的 <code class="function">std::bind1st()</code> 和
    <code class="function">std::bind2nd()</code> 函数，而 <a class="link" href="http://www.boost.org/libs/function/">Boost.Function</a>
    则提供了一个用于封装函数指针的类。 最后，<a class="link" href="http://www.boost.org/libs/lambda/">Boost.Lambda</a>
    则引入了一种创建匿名函数的方法。</p>
</div>
<hr>
<h2 class="title">
<a name="functionobjects_bind"></a>3.2. Boost.Bind</h2>
<div class="sect1">
<p>Boost.Bind 是这样的一个库，它简化了由C++标准中的 <code class="function">std::bind1st()</code> 和
    <code class="function">std::bind2nd()</code>
    模板函数所提供的一个机制：将这些函数与几乎不限数量的参数一起使用，就可以得到指定签名的函数。
    这种情形的一个最好的例子就是在C++标准中定义的多个不同算法。</p>
<pre class="programlisting">#include &lt;iostream&gt; 
#include &lt;vector&gt; 
#include &lt;algorithm&gt; 

void print(int i) 
{ 
  std::cout &lt;&lt; i &lt;&lt; std::endl; 
} 

int main() 
{ 
  std::vector&lt;int&gt; v; 
  v.push_back(1); 
  v.push_back(3); 
  v.push_back(2); 

  std::for_each(v.begin(), v.end(), print); 
} </pre>
<ul class="programlisting"><li><a class="programlisting" href="src/3.2.1/main.cpp">下载源代码</a></li></ul>
<p>算法 <code class="function">std::for_each()</code> 要求它的第三个参数是一个仅接受正好一个参数的函数或函数对象。
    如果 <code class="function">std::for_each()</code> 被执行，指定容器中的所有元素 - 在上例中，这些元素的类型为
    <code class="type">int</code> - 将按顺序被传入至 <code class="function">print()</code> 函数。
    但是，如果要使用一个具有不同签名的函数的话，事情就复杂了。 例如，如果要传入的是以下函数
    <code class="function">add()</code>，它要将一个常数值加至容器中的每个元素上，并显示结果。</p>
<pre class="programlisting">void add(int i, int j) 
{ 
  std::cout &lt;&lt; i + j &lt;&lt; std::endl; 
} </pre>
<p>由于 <code class="function">std::for_each()</code> 要求的是仅接受一个参数的函数，所以不能直接传入
    <code class="function">add()</code> 函数。 源代码必须要修改。</p>
<pre class="programlisting">#include &lt;iostream&gt; 
#include &lt;vector&gt; 
#include &lt;algorithm&gt; 
#include &lt;functional&gt; 

class add 
  : public std::binary_function&lt;int, int, void&gt; 
{ 
public: 
  void operator()(int i, int j) const 
  { 
    std::cout &lt;&lt; i + j &lt;&lt; std::endl; 
  } 
}; 

int main() 
{ 
  std::vector&lt;int&gt; v; 
  v.push_back(1); 
  v.push_back(3); 
  v.push_back(2); 

  std::for_each(v.begin(), v.end(), std::bind1st(add(), 10)); 
} </pre>
<ul class="programlisting"><li><a class="programlisting" href="src/3.2.2/main.cpp">下载源代码</a></li></ul>
<p>以上程序将值10加至容器 <var>v</var> 的每个元素之上，并使用标准输出流显示结果。
    源代码必须作出大幅的修改，以实现此功能：<code class="function">add()</code> 函数已被转换为一个派生自
    <code class="classname">std::binary_function</code> 的函数对象。</p>
<p>Boost.Bind 简化了不同函数之间的绑定。 它只包含一个 <code class="function">boost::bind()</code>
    模板函数，定义于 <code class="filename">boost/bind.hpp</code> 中。
    使用这个函数，可以如下实现以上例子：</p>
<pre class="programlisting">#include &lt;boost/bind.hpp&gt; 
#include &lt;iostream&gt; 
#include &lt;vector&gt; 
#include &lt;algorithm&gt; 

void add(int i, int j) 
{ 
  std::cout &lt;&lt; i + j &lt;&lt; std::endl; 
} 

int main() 
{ 
  std::vector&lt;int&gt; v; 
  v.push_back(1); 
  v.push_back(3); 
  v.push_back(2); 

  std::for_each(v.begin(), v.end(), boost::bind(add, 10, _1)); 
} </pre>
<ul class="programlisting"><li><a class="programlisting" href="src/3.2.3/main.cpp">下载源代码</a></li></ul>
<p>象 <code class="function">add()</code> 这样的函数不再需要为了要用于
    <code class="function">std::for_each()</code> 而转换为函数对象。 使用
    <code class="function">boost::bind()</code>，这个函数可以忽略其第一个参数而使用。</p>
<p>因为 <code class="function">add()</code> 函数要求两个参数，两个参数都必须传递给
    <code class="function">boost::bind()</code>。 第一个参数是常数值10，而第二个参数则是一个怪异的
    <var>_1</var>。</p>
<p><var>_1</var> 被称为占位符(placeholder)，定义于 Boost.Bind。 除了
    <var>_1</var>，Boost.Bind 还定义了 <var>_2</var> 和
    <var>_3</var>。 通过使用这些占位符，<code class="function">boost::bind()</code>
    可以变为一元、二元或三元的函数。 对于 <var>_1</var>,
    <code class="function">boost::bind()</code> 变成了一个一元函数 - 即只要求一个参数的函数。 这是必需的，因为
    <code class="function">std::for_each()</code> 正是要求一个一元函数作为其第三个参数。</p>
<p>当这个程序执行时，<code class="function">std::for_each()</code> 对容器 <var>v</var>
    中的第一个元素调用该一元函数。 元素的值通过占位符 <var>_1</var> 传入到一元函数中。 这个占位符和常数值被进一步传递到
    <code class="function">add()</code> 函数。 通过使用这种机制，<code class="function">std::for_each()</code>
    只看到了由 <code class="function">boost::bind()</code> 所定义的一元函数。 而
    <code class="function">boost::bind()</code> 本身则只是调用了另一个函数，并将常数值或占位符作为参数传入给它。</p>
<p>下面这个例子通过 <code class="function">boost::bind()</code> 定义了一个二元函数，用于
    <code class="function">std::sort()</code> 算法，该算法要求一个二元函数作为其第三个参数。</p>
<pre class="programlisting">#include &lt;boost/bind.hpp&gt; 
#include &lt;vector&gt; 
#include &lt;algorithm&gt; 

bool compare(int i, int j) 
{ 
  return i &gt; j; 
} 

int main() 
{ 
  std::vector&lt;int&gt; v; 
  v.push_back(1); 
  v.push_back(3); 
  v.push_back(2); 

  std::sort(v.begin(), v.end(), boost::bind(compare, _1, _2)); 
} </pre>
<ul class="programlisting"><li><a class="programlisting" href="src/3.2.4/main.cpp">下载源代码</a></li></ul>
<p>因为使用了两个占位符 <var>_1</var> 和 <var>_2</var>，所以
    <code class="function">boost::bind()</code> 定义了一个二元函数。 <code class="function">std::sort()</code>
    算法以容器 <var>v</var> 的两个元素来调用该函数，并根据返回值来对容器进行排序。 基于
    <code class="function">compare()</code> 函数的定义，容器将被按降序排列。</p>
<p>但是，由于 <code class="function">compare()</code> 本身就是一个二元函数，所以使用
    <code class="function">boost::bind()</code> 确是多余的。</p>
<pre class="programlisting">#include &lt;boost/bind.hpp&gt; 
#include &lt;vector&gt; 
#include &lt;algorithm&gt; 

bool compare(int i, int j) 
{ 
  return i &gt; j; 
} 

int main() 
{ 
  std::vector&lt;int&gt; v; 
  v.push_back(1); 
  v.push_back(3); 
  v.push_back(2); 

  std::sort(v.begin(), v.end(), compare); 
} </pre>
<ul class="programlisting"><li><a class="programlisting" href="src/3.2.5/main.cpp">下载源代码</a></li></ul>
<p>不过使用 <code class="function">boost::bind()</code> 还是有意义的。例如，如果容器要按升序排列而又不能修改
    <code class="function">compare()</code> 函数的定义。</p>
<pre class="programlisting">#include &lt;boost/bind.hpp&gt; 
#include &lt;vector&gt; 
#include &lt;algorithm&gt; 

bool compare(int i, int j) 
{ 
  return i &gt; j; 
} 

int main() 
{ 
  std::vector&lt;int&gt; v; 
  v.push_back(1); 
  v.push_back(3); 
  v.push_back(2); 

  std::sort(v.begin(), v.end(), boost::bind(compare, _2, _1)); 
} </pre>
<ul class="programlisting"><li><a class="programlisting" href="src/3.2.6/main.cpp">下载源代码</a></li></ul>
<p>该例子仅改变了占位符的顺序：<var>_2</var> 被作为第一参数传递，而
    <var>_1</var> 则被作为第二参数传递至
    <code class="function">compare()</code>，这样即可改变排序的顺序。</p>
</div>
<hr>
<h2 class="title">
<a name="functionobjects_ref"></a>3.3. Boost.Ref</h2>
<div class="sect1">
<p>本库 <a class="link" href="http://www.boost.org/doc/html/ref.html">Boost.Ref</a> 通常与
    Boost.Bind 一起使用，所以我把它们挨着写。 它提供了两个函数 - <code class="function">boost::ref()</code> 和
    <code class="function">boost::cref()</code> - 定义于 <code class="filename">boost/ref.hpp</code>.</p>
<p>当要用于 <code class="function">boost::bind()</code> 的函数带有至少一个引用参数时，Boost.Ref
    就很重要了。 由于 <code class="function">boost::bind()</code> 会复制它的参数，所以引用必须特别处理。</p>
<pre class="programlisting">#include &lt;boost/bind.hpp&gt; 
#include &lt;iostream&gt; 
#include &lt;vector&gt; 
#include &lt;algorithm&gt; 

void add(int i, int j, std::ostream &amp;os) 
{ 
  os &lt;&lt; i + j &lt;&lt; std::endl; 
} 

int main() 
{ 
  std::vector&lt;int&gt; v; 
  v.push_back(1); 
  v.push_back(3); 
  v.push_back(2); 

  std::for_each(v.begin(), v.end(), boost::bind(add, 10, _1, boost::ref(std::cout))); 
} </pre>
<ul class="programlisting"><li><a class="programlisting" href="src/3.3.1/main.cpp">下载源代码</a></li></ul>
<p>以上例子使用了上一节中的 <code class="function">add()</code> 函数。 不过这一次该函数需要一个流对象的引用来打印信息。
    因为传给 <code class="function">boost::bind()</code> 的参数是以值方式传递的，所以
    <var>std::cout</var> 不能直接使用，否则该函数会试图创建它的一份拷贝。</p>
<p>通过使用模板函数 <code class="function">boost::ref()</code>，象
    <var>std::cout</var> 这样的流就可以被以引用方式传递，也就可以成功编译上面这个例子了。</p>
<p>要以引用方式传递常量对象，可以使用模板函数 <code class="function">boost::cref()</code>。</p>
</div>
<hr>
<h2 class="title">
<a name="functionobjects_function"></a>3.4. Boost.Function</h2>
<div class="sect1">
<p>为了封装函数指针，<a class="link" href="http://www.boost.org/libs/function/">Boost.Function</a>
    提供了一个名为 <code class="classname">boost::function</code> 的类。 它定义于 <code class="filename">boost/function.hpp</code>，用法如下：</p>
<pre class="programlisting">#include &lt;boost/function.hpp&gt; 
#include &lt;iostream&gt; 
#include &lt;cstdlib&gt; 
#include &lt;cstring&gt; 

int main() 
{ 
  boost::function&lt;int (const char*)&gt; f = std::atoi; 
  std::cout &lt;&lt; f("1609") &lt;&lt; std::endl; 
  f = std::strlen; 
  std::cout &lt;&lt; f("1609") &lt;&lt; std::endl; 
} </pre>
<ul class="programlisting"><li><a class="programlisting" href="src/3.4.1/main.cpp">下载源代码</a></li></ul>
<p><code class="classname">boost::function</code> 可以定义一个指针，指向具有特定签名的函数。
    以上例子定义了一个指针 <var>f</var>，它可以指向某个接受一个类型为 <code class="type">const char*</code>
    的参数且返回一个类型为 <code class="type">int</code> 的值的函数。 定义完成后，匹配此签名的函数均可赋值给这个指针。 这个例程就是先将
    <code class="function">std::atoi()</code> 赋值给 <var>f</var>，然后再将它重赋值为
    <code class="function">std::strlen()</code>。</p>
<p>注意，给定的数据类型并不需要精确匹配：虽然 <code class="function">std::strlen()</code> 是以
    <code class="type">std::size_t</code> 作为返回类型的，但是它也可以被赋值给 <var>f</var>。</p>
<p>因为 <var>f</var> 是一个函数指针，所以被赋值的函数可以通过重载的
    <code class="methodname">operator()()</code> 操作符来调用。 取决于当前被赋值的是哪一个函数，在以上例子中将调用
    <code class="function">std::atoi()</code> 或 <code class="function">std::strlen()</code>。</p>
<p>如果 <var>f</var> 未赋予一个函数而被调用，则会抛出一个
    <code class="exceptionname">boost::bad_function_call</code> 异常。</p>
<pre class="programlisting">#include &lt;boost/function.hpp&gt; 
#include &lt;iostream&gt; 

int main() 
{ 
  try 
  { 
    boost::function&lt;int (const char*)&gt; f; 
    f(""); 
  } 
  catch (boost::bad_function_call &amp;ex) 
  { 
    std::cout &lt;&lt; ex.what() &lt;&lt; std::endl; 
  } 
} </pre>
<ul class="programlisting"><li><a class="programlisting" href="src/3.4.2/main.cpp">下载源代码</a></li></ul>
<p>注意，将值 0 赋给一个 <code class="classname">boost::function</code>
    类型的函数指针，将会释放当前所赋的函数。 释放之后再调用它也会导致
    <code class="exceptionname">boost::bad_function_call</code> 异常被抛出。
    要检查一个函数指针是否被赋值某个函数，可以使用 <code class="methodname">empty()</code> 函数或
    <code class="methodname">operator bool()</code> 操作符。</p>
<p>通过使用 Boost.Function，类成员函数也可以被赋值给类型为
    <code class="classname">boost::function</code> 的对象。</p>
<pre class="programlisting">#include &lt;boost/function.hpp&gt; 
#include &lt;iostream&gt; 

struct world 
{ 
  void hello(std::ostream &amp;os) 
  { 
    os &lt;&lt; "Hello, world!" &lt;&lt; std::endl; 
  } 
}; 

int main() 
{ 
  boost::function&lt;void (world*, std::ostream&amp;)&gt; f = &amp;world::hello; 
  world w; 
  f(&amp;w, boost::ref(std::cout)); 
} </pre>
<ul class="programlisting"><li><a class="programlisting" href="src/3.4.3/main.cpp">下载源代码</a></li></ul>
<p>在调用这样的一个函数时，传入的第一个参数表示了该函数被调用的那个特定对象。
    因此，在模板定义中的左括号后的第一个参数必须是该特定类的指针。 接下来的参数才是表示相应的成员函数的签名。</p>
<p>这个程序还使用了来自 Boost.Ref 库的 <code class="function">boost::ref()</code>，它提供了一个方便的机制向
    Boost.Function 传递引用。</p>
</div>
<hr>
<h2 class="title">
<a name="functionobjects_lambda"></a>3.5. Boost.Lambda</h2>
<div class="sect1">
<p>匿名函数 - 又称为 lambda 函数 - 已经在多种编程语言中存在，但 C++ 除外。 不过在 <a class="link" href="http://www.boost.org/libs/lambda/">Boost.Lambda</a>
    库的帮助下，现在在 C++ 应用中也可以使用它们了。</p>
<p>lambda 函数的目标是令源代码更为紧凑，从而也更容易理解。 以本章第一节中的代码例子为例。</p>
<pre class="programlisting">#include &lt;iostream&gt; 
#include &lt;vector&gt; 
#include &lt;algorithm&gt; 

void print(int i) 
{ 
  std::cout &lt;&lt; i &lt;&lt; std::endl; 
} 

int main() 
{ 
  std::vector&lt;int&gt; v; 
  v.push_back(1); 
  v.push_back(3); 
  v.push_back(2); 

  std::for_each(v.begin(), v.end(), print); 
} </pre>
<ul class="programlisting"><li><a class="programlisting" href="src/3.2.1/main.cpp">下载源代码</a></li></ul>
<p>这段程序接受容器 <var>v</var> 中的元素并使用 <code class="function">print()</code>
    函数将它们写出到标准输出流。 由于 <code class="function">print()</code> 只是写出一个简单的
    <code class="type">int</code>，所以该函数的实现相当简单。 严格来说，它是如此地简单，以致于如果可以在
    <code class="function">std::for_each()</code> 算法里面直接定义它的话，会更为方便； 从而省去增加一个函数的需要。
    另外一个好处是代码更为紧凑，使得算法与负责数据输出的函数不是局部性分离的。 Boost.Lambda 正好使之成为现实。</p>
<pre class="programlisting">#include &lt;boost/lambda/lambda.hpp&gt; 
#include &lt;iostream&gt; 
#include &lt;vector&gt; 
#include &lt;algorithm&gt; 

int main() 
{ 
  std::vector&lt;int&gt; v; 
  v.push_back(1); 
  v.push_back(3); 
  v.push_back(2); 

  std::for_each(v.begin(), v.end(), std::cout &lt;&lt; boost::lambda::_1 &lt;&lt; "\n"); 
} </pre>
<ul class="programlisting"><li><a class="programlisting" href="src/3.5.1/main.cpp">下载源代码</a></li></ul>
<p>Boost.Lambda 提供了几个结构来定义匿名函数。
    代码就被置于执行的地方，从而省去将它包装为一个函数再进行相应的函数调用的这些开销。 与原来的例子一样，这个程序将容器
    <var>v</var> 的所有元素写出至标准输出流。</p>
<p>与 Boost.Bind 相类似，Boost.Lambda 也定义了三个占位符，名为 <var>_1</var>,
    <var>_2</var> 和 <var>_3</var>。 但与 Boost.Bind
    不同的是，这些占位符是定义在单独的名字空间的。 因此，该例中的第一个占位符是通过
    <var>boost::lambda::_1</var> 来引用的。 为了满足编译器的要求，必须包含相应的头文件 <code class="filename">boost/lambda/lambda.hpp</code>。</p>
<p>虽然代码的位置位于 <code class="function">std::for_each()</code> 的第三个参数处，看起来很怪异，但
    Boost.Lambda 可以写出正常的 C++ 代码。 通过使用占位符，容器 <var>v</var> 的元素可以通过
    <code class="code">&lt;&lt;</code> 传给 <var>std::cout</var> 以将它们写出到标准输出流。</p>
<p>虽然 Boost.Lambda 非常强大，但也有一些缺点。 要在以上例子中插入换行的话，必须用 "\n" 来替代
    <code class="code">std::endl</code> 才能成功编译。 因为一元 <code class="code">std::endl</code> 模板函数所要求的类型不同于
    lambda 函数 <code class="code">std::cout &lt;&lt; boost::lambda::_1</code>
    的函数，所以在此不能使用它。</p>
<p>下一个版本的 C++ 标准很可能会将 lambda 函数作为 C++ 语言本身的组成部分加入，从而消除对单独的库的需要。
    但是在下一个版本到来并被不同的编译器厂商所采用可能还需要好几年。 在此之前，Boost.Lambda
    被证明是一个完美的替代品，从以下例子可以看出，这个例子只将大于1的元素写出到标准输出流。</p>
<pre class="programlisting">#include &lt;boost/lambda/lambda.hpp&gt; 
#include &lt;boost/lambda/if.hpp&gt; 
#include &lt;iostream&gt; 
#include &lt;vector&gt; 
#include &lt;algorithm&gt; 

int main() 
{ 
  std::vector&lt;int&gt; v; 
  v.push_back(1); 
  v.push_back(3); 
  v.push_back(2); 

  std::for_each(v.begin(), v.end(), 
    boost::lambda::if_then(boost::lambda::_1 &gt; 1, 
    std::cout &lt;&lt; boost::lambda::_1 &lt;&lt; "\n")); 
} </pre>
<ul class="programlisting"><li><a class="programlisting" href="src/3.5.2/main.cpp">下载源代码</a></li></ul>
<p>头文件 <code class="filename">boost/lambda/if.hpp</code>
    定义了几个结构，允许在 lambda 函数内部使用 <code class="code">if</code> 语句。 最基本的结构是
    <code class="function">boost::lambda::if_then()</code> 模板函数，它要求两个参数：第一个参数对条件求值 -
    如果为真，则执行第二个参数。 如例中所示，每个参数本身都可以是 lambda 函数。</p>
<p>除了 <code class="function">boost::lambda::if_then()</code>, Boost.Lambda 还提供了
    <code class="function">boost::lambda::if_then_else()</code> 和
    <code class="function">boost::lambda::if_then_else_return()</code> 模板函数 - 它们都要求三个参数。
    另外还提供了用于实现循环、转型操作符，甚至是 <code class="code">throw</code> - 允许 lambda 函数抛出异常 -
    的模板函数。</p>
<p>虽然可以用这些模板函数在 C++ 中构造出复杂的 lambda 函数，但是你必须要考虑其它方面，如可读性和可维护性。
    因为别人需要学习并理解额外的函数，如用 <code class="function">boost::lambda::if_then()</code> 来替代已知的 C++
    关键字 <code class="code">if</code> 和 <code class="code">else</code>，lambda 函数的好处通常随着它的复杂性而降低。
    多数情况下，更为合理的方法是用熟悉的 C++ 结构定义一个单独的函数。</p>
</div>
<hr>
<h2 class="title">
<a name="functionobjects_exercises"></a>3.6. 练习</h2>
<div class="sect1">
<p class="solution">
              You can buy 
              <a target="_top" href="http://en.highscore.de/shop/index.php?p=boost-solution">solutions to all exercises</a>
              in this book as a ZIP file. 
            </p>
<ol>
<li class="listitem">
<p>简化以下程序，将函数对象 <code class="classname">divide_by</code> 转换为一个函数，并将
        <code class="code">for</code> 循环替换为用一个标准的 C++ 算法来输出数据：</p>
<pre class="programlisting">#include &lt;algorithm&gt; 
#include &lt;functional&gt; 
#include &lt;vector&gt; 
#include &lt;iostream&gt; 

class divide_by 
  : public std::binary_function&lt;int, int, int&gt; 
{ 
public: 
  int operator()(int n, int div) const 
  { 
    return n / div; 
  } 
}; 

int main() 
{ 
  std::vector&lt;int&gt; numbers; 
  numbers.push_back(10); 
  numbers.push_back(20); 
  numbers.push_back(30); 

  std::transform(numbers.begin(), numbers.end(), numbers.begin(), std::bind2nd(divide_by(), 2)); 

  for (std::vector&lt;int&gt;::iterator it = numbers.begin(); it != numbers.end(); ++it) 
    std::cout &lt;&lt; *it &lt;&lt; std::endl; 
} </pre>
<ul class="programlisting"><li><a class="programlisting" href="src/3.6.1/main.cpp">下载源代码</a></li></ul>
</li>
<li class="listitem">
<p>简化以下程序，将两个 <code class="code">for</code> 循环都替换为标准的 C++ 算法：</p>
<pre class="programlisting">#include &lt;string&gt; 
#include &lt;vector&gt; 
#include &lt;iostream&gt; 

int main() 
{ 
  std::vector&lt;std::string&gt; strings; 
  strings.push_back("Boost"); 
  strings.push_back("C++"); 
  strings.push_back("Libraries"); 

  std::vector&lt;int&gt; sizes; 

  for (std::vector&lt;std::string&gt;::iterator it = strings.begin(); it != strings.end(); ++it) 
    sizes.push_back(it-&gt;size()); 

  for (std::vector&lt;int&gt;::iterator it = sizes.begin(); it != sizes.end(); ++it) 
    std::cout &lt;&lt; *it &lt;&lt; std::endl; 
} </pre>
<ul class="programlisting"><li><a class="programlisting" href="src/3.6.2/main.cpp">下载源代码</a></li></ul>
</li>
<li class="listitem">
<p>简化以下程序，修改变量 <var>processors</var> 的类型，并将
        <code class="code">for</code> 循环替换为标准的 C++ 算法：</p>
<pre class="programlisting">#include &lt;vector&gt; 
#include &lt;iostream&gt; 
#include &lt;cstdlib&gt; 
#include &lt;cstring&gt; 

int main() 
{ 
  std::vector&lt;int(*)(const char*)&gt; processors; 
  processors.push_back(std::atoi); 
  processors.push_back(reinterpret_cast&lt;int(*)(const char*)&gt;(std::strlen)); 

  const char data[] = "1.23"; 

  for (std::vector&lt;int(*)(const char*)&gt;::iterator it = processors.begin(); it != processors.end(); ++it) 
    std::cout &lt;&lt; (*it)(data) &lt;&lt; std::endl; 
} </pre>
<ul class="programlisting"><li><a class="programlisting" href="src/3.6.3/main.cpp">下载源代码</a></li></ul>
</li>
</ol>
</div>
</div>
<hr class="hrfoot">
<p class="copyright">版权 © 2008-2010 
        <a class="link" href="mailto:boris@highscore.de">Boris Schäling</a>
      </p>
</body>
</html>
